package com.jshop.seckill.timer;

import com.Jshop.common.utils.DateUtil;
import com.Jshop.common.utils.JsonUtils;
import com.jshop.seckill.client.SkuFeign;
import com.jshop.seckill.mapper.SeckillGoodsMapper;
import com.jshop.seckill.pojo.SeckillGoods;
import com.leyou.item.pojo.Sku;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class SeckillGoodsPushTask {

    @Resource
    private SeckillGoodsMapper mapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private SkuFeign skuFeign;

    /**
     * @Description 缓存预热
     * 定时将秒杀商品加载到redis中
     * 查询从当前时间开始，往后延续4个时间菜单间隔，也就是一共只查询5个时间段抢购商品数据，并压入缓存
     * 秒 分 小时 日 周 月
     * 5秒执行一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void loadGoodsPushRedis() {
        //获取时间段集合
        //Sat Nov 13 18:00:00 CST 2021
        //Sat Nov 13 20:00:00 CST 2021
        List<Date> dateMenus = DateUtil.getDateMenus();
        //循环时间段
        for (Date startTime : dateMenus) {
            // namespace = SeckillGoods_2021111318 主Key HashKey:SecGoodId value: Object 代表Redis预加载时间
            //2021111318
            //2021111320
            String extName = DateUtil.data2str(startTime,DateUtil.PATTERN_YYYY_MM_DD_HH);
            //根据时间段数据查询对应的秒杀商品数据
            Example example = new Example(SeckillGoods.class);
            Example.Criteria criteria = example.createCriteria();
            // 1)库存 > 0
            criteria.andGreaterThan("stock",0);
            // 2)秒杀商品定义的开始时间 <= 活动开始时间
            criteria.andGreaterThanOrEqualTo("startTime", startTime);
            // 3)商品结束时间 < 开始时间+2小时
            criteria.andLessThan("endTime", DateUtil.addDateHour(startTime,2));
            // 4)排除之前已经加载到Redis缓存中的商品数据
            BoundHashOperations<String, String, Object> hashOps =
                    this.redisTemplate.boundHashOps("SeckillGoods_" + extName);
            Set<String> keys = hashOps.keys();

            if(keys != null && keys.size() > 0){
                criteria.andNotIn("id", keys);
            }
            //查询数据
            List<SeckillGoods> seckillGoods = mapper.selectByExample(example);
            if (seckillGoods != null && seckillGoods.size() != 0){
                System.out.println("命中秒杀商品" + seckillGoods);
                List<Long> skuIds = seckillGoods.stream().map(SeckillGoods::getSkuId).collect(Collectors.toList());
                //dofeign调用 查询SKu信息 含有商品展示的所有必须信息
                List<Sku> skus = this.skuFeign.findBySkuIds(skuIds);
                Map<Long, Sku> skuMap = skus.stream().collect(Collectors.toMap(Sku::getId, sku -> sku));
                //回赋值
                for (SeckillGoods seckillGood : seckillGoods) {
                    seckillGood.setSku(skuMap.get(seckillGood.getSkuId()));
                }
                //将秒杀商品数据存入到Redis缓存
                for (SeckillGoods seckillGood : seckillGoods) {
                    //hash put
                    hashOps.put(seckillGood.getId().toString(), JsonUtils.serialize(seckillGood));
                    String o = (String)hashOps.get(seckillGood.getId().toString());
                    SeckillGoods parse = JsonUtils.parse(o, SeckillGoods.class);
                    System.out.println("redis 秒杀商品预热 取值：" + o);
                    System.out.println("反序列化取值：" + parse);
                    //设置过期时间 2个小时
//                redisTemplate.expireAt("SeckillGoods_" + extName, DateUtil.addDateHour(startTime, 2));
                    //商品库存在Redis中存放 防止超卖问题

                }
            }
        }
    }

    /**
     * 获取秒杀商品数量的数组
     * @return
     * @param num
     */
    public Byte[] getGoodsNumber(int num) {
        Byte[] arr = new Byte[num];
        for (int i = 0; i < num; i++) {
            arr[i] = '0';
        }
        return arr;
    }

}
